package com.example.h264.H264;

import android.media.MediaCodec;
import android.media.MediaFormat;
import android.view.Surface;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;

//解码是耗时操作 交给线程
public class H264Player implements Runnable{
    private String path;
    //数据源
     MediaCodec mediaCodec;
    //解码器
    private Surface surface;
    //显示目标

    public H264Player(String path, Surface surface) {
        this.path = path;
        this.surface = surface;
        try {
           mediaCodec = MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
           MediaFormat mediaFormat = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_VIDEO_AVC,
                   100,100);
           mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE,15);
           //MediaCrypto 加密
           mediaCodec.configure(mediaFormat,surface,null,0);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void play(){
        mediaCodec.start();
        new Thread(this).start();
    }

    @Override
    public void run() {
        try {
            decodeH264();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void decodeH264() {
        byte[] bytes = null;
        try {
            bytes = getBytes(path);
        } catch (Exception e) {
            e.printStackTrace();
        }
        int startIndex = 0;
        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
        while (true){
            //        ByteBuffer[] byteBuffers = mediaCodec.getInputBuffers();//获取缓存容器列表
            //获取可用容器  在等待时间过后返回-1代表无可用
            int index = mediaCodec.dequeueInputBuffer(10000);
            if (index >= 0){
                int nextFrameStart = findByFrame(bytes,startIndex+4,bytes.length);
//            ByteBuffer bf = byteBuffers[index];
                ByteBuffer bf = mediaCodec.getInputBuffer(index);
                //以帧为单位交给DSP处理 分隔符为00 00 00 01   或 00 00 01
                int length = nextFrameStart - startIndex;
                bf.put(bytes,startIndex,length);
                mediaCodec.queueInputBuffer(index,0,length,0,0);
                startIndex = nextFrameStart;
            }
            //返回值若大于0 则代表解码成功
            int outIndex = mediaCodec.dequeueOutputBuffer(info,10000);
            if (outIndex >= 0){
                try {
                    //控制输出帧数(即播放速度)
                    Thread.sleep(33);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //此处参数为true 则会直接渲染到之前配置的surface中
                //若是编码缓冲区未达到刷新标准 则不会输出  每个设备的标准并不相同
                mediaCodec.releaseOutputBuffer(index,true);
            }
        }
    }
    private int findByFrame(byte[] bytes, int start, int total){
        for(int i = start; i <= total - 4; i++){
            if (bytes[i] == 0x00 && bytes[i+1] == 0x00 && bytes[i+2] == 0x00 && bytes[i+3] == 0x01
                    ||bytes[i] == 0x00 && bytes[i+1] == 0x00 && bytes[i+2] == 0x01){
                return i;
            }
        }
        return -1;

    }

    //读取文件中每个字节
    private byte[] getBytes(String path) throws IOException {
        InputStream is = new DataInputStream(new FileInputStream(path));
        int len;
        int size = 1024;
        byte[] buf;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        buf = new byte[size];
        while ((len = is.read(buf,0,size))!= -1){
            bos.write(buf,0,size);
        }
        buf = bos.toByteArray();
        return buf;
    }
}
